package appUtils;

import android.text.TextUtils;
import android.util.Base64;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import apiUtils.models.PayExceptionType;
import apiUtils.models.PayInfo;

/**
 * Created by Administrator on 2016/5/16 0016.
 * code fromat and modify codes by Joe on 2017/5/27
 */
public final class PayAESUtil {
    public static final String KEY = "66af8593f42b01b3ee815ad8be980e3c";
    public static final String VECTOR = "04c52bed86e11f9e";
    private static final String LOG_TAG = "PayAESUtil ";
    private static final String CHAR_SET_NAME = "utf-8";
    private static final String CHARSET_NAME = "UTF-8";
    private static Cipher mCipher = null;

    static {
        try {
            mCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            log("static NoSuchAlgorithmException = " + e.getMessage());
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
            log("static NoSuchPaddingException = " + e.getMessage());
        }
    }

    private static void log(String str) {
        String logStr = LOG_TAG + str;
        LogUtil.log(logStr);
    }

    /**
     * @param content  encrypt content
     * @param password key
     * @param iv       vector
     * @return byte[]
     */
    private static byte[] encrypt(String content, String password, String iv) {
        if (TextUtils.isEmpty(password) || TextUtils.isEmpty(iv)) {
            password = KEY;
            iv = VECTOR;
        }
        try {
            SecretKeySpec key = new SecretKeySpec(password.getBytes(CHAR_SET_NAME), "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(CHAR_SET_NAME));
            byte[] byteContent = content.getBytes(CHAR_SET_NAME);
            mCipher.init(Cipher.ENCRYPT_MODE, key, ivSpec);
            return mCipher.doFinal(byteContent);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
            log("encrypt InvalidKeyException = " + e.getMessage());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            log("encrypt UnsupportedEncodingException = " + e.getMessage());
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
            log("encrypt IllegalBlockSizeException = " + e.getMessage());
        } catch (BadPaddingException e) {
            e.printStackTrace();
            log("encrypt BadPaddingException = " + e.getMessage());
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
            log("encrypt InvalidAlgorithmParameterException = " + e.getMessage());
        }
        return null;
    }

    /**
     * @param content  decrypt content
     * @param password key
     * @param iv       vector
     * @return byte[]
     */
    private static byte[] decrypt(byte[] content, String password, String iv) {
        if (TextUtils.isEmpty(password) || TextUtils.isEmpty(iv)) {
            password = KEY;
            iv = VECTOR;
        }
        try {
            SecretKeySpec key = new SecretKeySpec(password.getBytes(CHAR_SET_NAME), "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(CHAR_SET_NAME));
            mCipher.init(Cipher.DECRYPT_MODE, key, ivSpec);
            return mCipher.doFinal(content);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
            log("decrypt InvalidKeyException = " + e.getMessage());
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
            log("decrypt IllegalBlockSizeException = " + e.getMessage());
        } catch (BadPaddingException e) {
            e.printStackTrace();
            log("decrypt BadPaddingException = " + e.getMessage());
        } catch (InvalidAlgorithmParameterException e) {
            e.printStackTrace();
            log("decrypt InvalidAlgorithmParameterException = " + e.getMessage());
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
            log("decrypt UnsupportedEncodingException = " + e.getMessage());
        }
        return null;
    }

    /**
     * AES 加密
     *
     * @param tag  Tag
     * @param info infoMessage
     * @return String
     */
    public static String encryptAES(String tag, String info) {
        if (TextUtils.isEmpty(info)) {
            LogUtil.log(tag + " encrypt info = null");
            ToastUtil.showShort(PayExceptionType.INVALID_TOKEN.getMessage());
            return null;
        }
        byte[] cipherText = encrypt(info, PayInfo.getInstance().getKeyAES(), PayInfo.getInstance().getVectorAES());
        if (null == cipherText) {
            ToastUtil.showShort(PayExceptionType.ENCRYPT_EXCEPTION.getMessage());
            return null;
        }
        String dest = Base64.encodeToString(cipherText, Base64.DEFAULT);
        // just replace special character "+" instead of "%2B"
        String str = dest.replace("+", "-").replace("/", "_").replace("=", "~").
                replace("\r", "").replace("\n", "");
        try {
            return URLEncoder.encode(str, CHARSET_NAME);
        } catch (UnsupportedEncodingException e) {
            LogUtil.log(tag + " UnsupportedEncodingException = " + e.getMessage());
            ToastUtil.showShort(PayExceptionType.DATA_EXCEPTION.getMessage());
            e.printStackTrace();
            return null;
        }
    }

    /**
     * AES解密
     *
     * @param tag Tag
     * @param msg message
     * @return String
     * @throws UnsupportedEncodingException Exception
     */
    public static String decryptAES(String tag, String msg) throws UnsupportedEncodingException {
        msg = msg.replace("-", "+").replace("_", "/").replace("~", "=");
        if (TextUtils.isEmpty(msg)) {
            LogUtil.log(tag + " onResponse msg = null");
            ToastUtil.showShort(PayExceptionType.INVALID_TOKEN.getMessage());
            return null;
        } else {
            LogUtil.log(tag + " onResponse msg = " + msg);
            byte[] decryptFrom = Base64.decode(msg, Base64.DEFAULT);
            byte[] decryptResult = decrypt(decryptFrom, PayInfo.getInstance().getKeyAES(), PayInfo.getInstance().getVectorAES());
            if (null == decryptResult) {
                LogUtil.log(tag + " decryptResult exception");
                ToastUtil.showShort(PayExceptionType.DECRYPT_EXCEPTION.getMessage());
                return null;
            }
            return new String(decryptResult, CHARSET_NAME);
        }
    }
}
